package com.seeyon.cap4.form.bean.fieldCtrl;

import com.seeyon.cap4.form.bean.FormAuthViewFieldBean;
import com.seeyon.cap4.form.bean.FormDataMasterBean;
import com.seeyon.cap4.form.bean.FormFieldBean;
import com.seeyon.cap4.form.bean.FormFieldComEnum;
import com.seeyon.cap4.form.bean.ParamDefinition;
import com.seeyon.cap4.form.util.Enums;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.exceptions.BusinessException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * Created by chenxb on 2017-8-14.
 * 自定义控件抽象父类，所有的自定义控件都继承此抽象类
 */
public abstract class FormFieldCustomCtrl extends FormFieldCtrl {

    public List<ParamDefinition> params = new ArrayList<ParamDefinition>();

    @Override
    public boolean canInRelatedDataCondition(){
        return false;
    }
    /**
     * 自定义控件所属插件的id，对应cfgHome/plugin/插件配置目录/pluginCfg.xml中的id值
     */
    public String pluginId;

    private Enums.ButtonType buttonType;

    public Enums.ButtonType getButtonType() {
        return buttonType;
    }

    public void setButtonType(Enums.ButtonType buttonType) {
        this.buttonType = buttonType;
    }

    @Override
    public boolean authNotNullAndValIsNull(FormDataMasterBean formDataMasterBean, FormFieldBean field, FormAuthViewFieldBean authViewFieldBean, Object val) {
        return super.authNotNullAndValIsNull(formDataMasterBean, field, authViewFieldBean, val);
    }

    /**
     * 控件初始化接口
     * 使用举例：配在接口中定义自定义控件在在表单编辑器中有哪些控件属性需要置
     */
    @Override
    public abstract void init();


    /**
     * 运行态生成控件的值，比如电子发票等控件在运行的时候需要生成一个uuid
     *
     * @param oldVal
     * @return
     */
    public Object genVal(Object oldVal) {
        return oldVal;
    }

    /**
     * 用于判断是否支持列表查询，默认支持，如果不支持需要具体控件重写此接口，返回false
     * @return
     */
    @Override
    public boolean canInSearchCondition(){
        return false;
    }

    /**
     * 是否能参与计算
     *
     * @return
     */
    @Override
    public boolean canInCalc() {
        return true;
    }

    /**
     * 定义控件是否能参与明细表，默认支持，如果不支持重写此方法返回false
     *
     * @return
     */
    @Override
    public boolean canInSubTable() {
        return true;
    }

    /**
     * 是否支持套红，自定义控件默认false，如果支持需要重新接口返回true
     *
     * @return
     */
    public boolean canInjectionWord() {
        return false;
    }

    /**
     * 是否支持分支
     *
     * @return
     */
    public boolean canInWorkFlowBranch() {
        return false;
    }

    /**
     * 某些场景，比如流程分支匹配的时候，将当前自定义控件作为什么控件来处理。
     * 默认返回自身控件类型，实现控件的时候如果有需要，可以重写此接口返回其他标准控件类型。
     * @return
     */
    public String mappingStandardCtrlType(){
        return this.getKey();
    }

    /**
     * 自定义是否能参与触发会议
     * @return
     */
    public boolean canInMeetingTrigger(){
        return false;
    }

    /**
     * 获取PC端自定义控件运行态资源注入信息
     * jsUri:定义PC端表单运行态加载第三方JavaScript的路径
     * cssUri：定义PC端表单运行态加载第三方CSS的路径
     * initMethod:定义PC端表单运行态第三方js入口方法名称
     *
     * @return
     */
    public abstract String getPCInjectionInfo();

    /**
     * 获取移动端自定义控件运行态资源注入信息
     * path：'http://'+m3应用包mainifest.json中的urlSchemes的值+'v'+m3应用包mainifest.json中的version的值
     * weixinpath: 微信端打开的时候使用的m3/apps/v5/自定义控件移动端资源目录名称/,weixinpath配置的就是此自定义控件移动端资源目录名称
     * jsUri:移动端表单运行态加载第三方JavaScript的路径
     * initMethod:定义M3端表单运行态第三方js入口方法名称
     * * nameSpace:定义M3端表单运行态命名空间
     *
     * @return
     */
    public abstract String getMBInjectionInfo();


    /**
     * 获取控件对应数据库所需长度
     * 注意：一旦自定义控件长度定好，上线部署到OA环境中之后，
     * 此接口返回的长度不允许改变，因为上线之后如果有表单使用
     * 了此自定义控件，就会在数据库中创建字段长度为此指定长度
     * 的数据列。
     *
     * @return
     */
    public abstract String getFieldLength();

    /**
     * 控件类型名称
     */
    @Override
    public final InputTypeCategory getCategory() {
        return InputTypeCategory.CUSTOM;
    }

    /**
     * 此接口判断控件是否可用，true：可用，false：不可用
     * @return
     */
    @Override
    public boolean canUse() {
        //return AppContext.hasPlugin("cap4") && (Boolean) SysFlag.valueOf("form_showCustom_control").getFlag();
        return AppContext.hasPlugin("cap4") && this.isValid();
        //return AppContext.hasPlugin("cap4");
    }

    @Override
    public boolean canUse(Enums.FormType formType) {
        return canUse();
    }

    @Override
    public final Integer getSort() {
        return FormFieldComEnum.CUSTOM_CONTROL.ordinal();
    }

    /**
     * 控件是否支持关联（表间关联，关联表单能否将当前这个控件设置为映射字段）
     * @return
     */
    @Override
    public boolean canRelation() {
        return true;
    }

    /**
     * 是否能作为查询统计的输出项，默认不支持，如果当前控件需要在查询统计中输出，则需要重写此接口返回true
     * @return
     */
    public boolean canShowInReport(){
        return true;
    }

    /**
     * 是否支持扩展函数（表单计算公式中的扩展函数）
     * @return
     */
    @Override
    public boolean canExtend() {
        return true;
    }

    /**
     * 是否是附件类控件（附件类控件比如：上传附件控件、上传图片控件，如果此接口返回true，表示在调用CTP平台的附件上传组件之后，此字段只存放ctp_attachment表中的sub_reference的值）
     * @return
     */
    @Override
    public boolean isAttachment() {
        return false;
    }

    /**
     * 是否能作为二维码组成项
     */
    @Override
    public boolean barcodeContent() {
        return false;
    }

    @Override
    public Enums.FieldType[] getFieldType() {
        return new Enums.FieldType[]{Enums.FieldType.VARCHAR};
    }

    public List<ParamDefinition> getParams() {
        return params;
    }

    /**
     * 添加控件设置态属性，属性由ParamDefinition进行描述
     * @param d
     */
    public void addDefinition(ParamDefinition d) {
        params.add(d);
    }

    /**
     * 控件所属插件id,目前自定义控件实现机制有两种：
     * 1、由插件机制实现，由插件机制实现的自定义控件需要在web-inf/lib/cfgHome/plugin/目录下创建插件定义信息配置文件，其中会创建一个叫pluginCfg.xml的配置文件，此处的pluginId是配置文件中的id；
     * 2、另外一种是使用component,和插件机制类似，只不过配置文件路径是对应的是web-inf/lib/cfgHome/component/xxxx/pluginCfg.xml.
     * @return
     */
    public String getPluginId() {
        return pluginId;
    }

    /**
     * 设置控件所属项目插件的id
     * @param pluginId
     */
    public void setPluginId(String pluginId) {
        this.pluginId = pluginId;
    }

    /**
     * 将控件信息转换为json（表单编辑器的控件页签中需要用到）
     * @return
     */
    @Override
    public Map<String, Object> toJsonObject() {
        Map<String, Object> customCtrl = super.toJsonObject();
        customCtrl.put("text", this.getText());
        customCtrl.put("fieldLength", this.getFieldLength());
        customCtrl.put("fieldType", this.getFieldType()[0].getKey());
        List<ParamDefinition> params = this.getParams();
        List<Map<String, Object>> paramsJsonObjs = new ArrayList<Map<String, Object>>();
        for (ParamDefinition param : params) {
            paramsJsonObjs.add(param.toJsonObject());
        }
        if(this.isButton()){
            customCtrl.put("btnType",this.getButtonType().getKey());
        }
        customCtrl.put("canInSubTable", this.canInSubTable());
        customCtrl.put("paramDefinitions", paramsJsonObjs);
        return customCtrl;
    }

    /**
     * 自定义控件保存方法，默认空实现，如果有需要，在自身的控件实现类中重写此方法
     * @param params 参数
     */
    public void handleSaving(Map<String,Object> params) throws BusinessException {
        return;
    }

    /**
     * 保存并复制接口，如果自定义控件支持保存并复制功能，需要重写此接口
     * @param params
     */
    public void saveAndCopy(Map<String,Object> params){
        return ;
    }

    /**
     * 后台刷新接口，如果自定义控件需要后台刷新自定义控件内容，需要重写此接口
     * 供批量刷新、批量修改、触发关系使用
     * @param params
     */
    public void refresh(Map<String,Object> params) throws BusinessException {
        return ;
    }

    /**
     * 自定义控件分是否按钮类，如果是按钮类，则重写此接口返回true
     * @return
     */
    public boolean isButton(){
        return false;
    }



}